﻿using System;
using System.Windows;

using iStudio.Library.Dsp;
using iStudio.Structure.Engine;
using iStudio.Structure.Wave;

namespace iStudio.Module.Effect
{
    /// <summary>
    /// Interaction logic for EffectWindow.xaml
    /// </summary>
    public partial class EffectWindow
    {
        public EffectWindow(Structure.Engine.Module module): base(module)
        {
            InitializeComponent ();

            Title = "Effects";

            convolution_track1.ItemsSource = AudioEngine.Instance.Project.TrackList;
            convolution_track2.ItemsSource = AudioEngine.Instance.Project.TrackList;
        }

        private void ButtonConvolveClick(object sender, RoutedEventArgs e)
        {
            //
            // Perform convolution between two tracks
            //

            try
            {
                WaveTrack trackOne = AudioEngine.Instance.Project.TrackList[convolution_track1.SelectedIndex];
                WaveTrack trackTwo = AudioEngine.Instance.Project.TrackList[convolution_track2.SelectedIndex];

                //
                // Use complete track API, not chunk API
                //

                float[] trackOneSamples = new float[trackOne.Length];
                float[] trackTwoSamples = new float[trackTwo.Length];

                for (int i = 0; i < Math.Max (trackOne.Length, trackTwo.Length); i++)
                {
                    if (i < trackOne.Length)
                    {
                        trackOneSamples[i] = trackOne.GetSample (i);
                    }

                    if (i < trackTwo.Length)
                    {
                        trackTwoSamples[i] = trackTwo.GetSample (i);
                    }
                }


                float[] convolved = Convolution.Convolve (trackOneSamples, trackTwoSamples);

                for (int i = 0; i < convolved.Length; i++)
                {
                    trackOne.SetSample (i, convolved[i]);
                }

                ModuleApi.ConsoleLog ("Performed impulse response on track: " + trackOne);
            }
            catch (Exception ex)
            {
                MessageBox.Show ("Convolution error: " + ex.Message);
            }
            
        }

        private void ButtonFadeeffectClick(object sender, RoutedEventArgs e)
        {
            if ( (check_fadein.IsChecked == false) && (check_fadeout.IsChecked == false) )
            {
                ModuleApi.ConsoleLog ("No effect was selected, aborting ...");

                return;
            }

             foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
             {
                 foreach (WaveChunk chunk in track.TrackChunks)
                 {
                     if (chunk.IsSelected)
                     {
                         float[] buffer = chunk.WaveBuffer.ToArray ();

                         if (check_fadein.IsChecked == true)
                         {
                             Library.Dsp.Effect.FadeIn (buffer, track.SampleRate, Convert.ToInt32 (fade_length.Text));
                         }
                         
                         if (check_fadeout.IsChecked == true)
                         {
                             Library.Dsp.Effect.FadeOut (buffer, track.SampleRate, Convert.ToInt32(fade_length.Text));
                         }

                         //
                         // Rewrite samples
                         //

                         //
                         // TODO: Optimize - change only samples that were changed
                         //

                         chunk.WaveBuffer.SetFrameChange(128);

                         for (int i = 0; i < chunk.WaveBuffer.Count; i++)
                         {
                             chunk.WaveBuffer[i] = buffer[i];
                         }
                         chunk.WaveBuffer.SetFrameChange(0);

                         ModuleApi.ConsoleLog("Fade effect done on chunk with length: " + fade_length.Text);
                     }
                 }
             }
        }

        private void ButtonFlangereffectClick(object sender, RoutedEventArgs e)
        {
            foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
            {
                foreach (WaveChunk chunk in track.TrackChunks)
                {
                    if (chunk.IsSelected)
                    {
                        float[] buffer = chunk.WaveBuffer.ToArray();

                        Library.Dsp.Effect.Flanger (buffer, track.SampleRate, Convert.ToInt32 (flanger_delay.Text), Convert.ToInt32 (flanger_freq.Text), 0.5);

                        //
                        // Rewrite samples
                        //

                        //
                        // TODO: Optimize - change only samples that were changed
                        //

                        chunk.WaveBuffer.SetFrameChange(128);

                        for (int i = 0; i < chunk.WaveBuffer.Count; i++)
                        {
                            chunk.WaveBuffer[i] = buffer[i];
                        }
                        chunk.WaveBuffer.SetFrameChange(0);

                        ModuleApi.ConsoleLog("Flanger effect applied to chunk: " + chunk);
                    }
                }
            }
        }

        private void ButtonChoruseffectClick(object sender, RoutedEventArgs e)
        {

            int[] delays = Library.Text.TextToIntArray (chorus_delays.Text);
            float[] amplitudes = Library.Text.TextToFloatArray (chorus_strength.Text);

            foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
            {
                foreach (WaveChunk chunk in track.TrackChunks)
                {
                    if (chunk.IsSelected)
                    {
                        float[] buffer = chunk.WaveBuffer.ToArray ();

                        buffer = Library.Dsp.Effect.Chorus (buffer, track.SampleRate, amplitudes, delays);

                        //
                        // Rewrite samples
                        //

                        //
                        // TODO: Optimize - change only samples that were changed
                        //

                        chunk.WaveBuffer.SetFrameChange (128);

                        for (int i = 0; i < chunk.WaveBuffer.Count; i++)
                        {
                            chunk.WaveBuffer[i] = buffer[i];
                        }

                        if (chunk.WaveBuffer.Count < buffer.Length)
                        {
                            for (int i = chunk.WaveBuffer.Count; i < buffer.Length; i++)
                            {
                                chunk.WaveBuffer.Add (buffer[i]);
                            }
                        }

                        chunk.WaveBuffer.SetFrameChange (0);

                        ModuleApi.ConsoleLog ("Chorus effect applied to chunk: " + chunk);
                    }
                }
            }
        }

        //private void ButtonAmplifyClick(object sender, RoutedEventArgs e)
        //{
        //    int factor = Convert.ToInt32(amplify_factor.Text);

        //    //
        //    // Go through all selected wave chunks
        //    //

        //    foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
        //    {
        //        foreach (WaveChunk chunk in track.TrackChunks)
        //        {
        //            if (chunk.IsSelected)
        //            {
        //                //
        //                // Set frame change to 128, so each sample changed will not be recalculated
        //                //
        //                chunk.WaveBuffer.SetFrameChange (128);

        //                for (int i = 0; i < chunk.WaveBuffer.Count; i++)
        //                {
        //                    float value = factor * chunk.WaveBuffer[i];
                            
        //                    //
        //                    // Cut away the samples over the limit
        //                    //

        //                    if (value > 1.0f)
        //                    {
        //                        value = 1.0f;
        //                    }
        //                    else if (value < -1.0f)
        //                    {
        //                        value = -1.0f;
        //                    }

        //                    chunk.WaveBuffer[i] = value;
        //                }

        //                chunk.WaveBuffer.SetFrameChange (0);

        //                ModuleApi.ConsoleLog ("Amplified chunk with factor: " + factor.ToString("N2"));
        //            }
        //        }
        //    }
        //}

        //private void ButtonNormalizeClick(object sender, RoutedEventArgs e)
        //{
        //    const float max = 1.0f;

        //    foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
        //    {
        //        foreach (WaveChunk chunk in track.TrackChunks)
        //        {
        //            if (chunk.IsSelected)
        //            {
        //                //
        //                // Finding maximum value
        //                //

        //                float maximumValue = chunk.WaveBuffer[0];
        //                float minimumValue = chunk.WaveBuffer[0];

        //                foreach (float t in chunk.WaveBuffer)
        //                {
        //                    if (t > maximumValue)
        //                    {
        //                        maximumValue = t;
        //                    }

        //                    if (t < minimumValue)
        //                    {
        //                        minimumValue = t;
        //                    }
        //                }

        //                //
        //                // Calculate the factor
        //                //

        //                float factor = max / maximumValue;

        //                //
        //                // Multiply the factor
        //                //

        //                chunk.WaveBuffer.SetFrameChange (128);

        //                for (int i = 0; i < chunk.WaveBuffer.Count; i++)
        //                {
        //                    chunk.WaveBuffer[i] = factor * chunk.WaveBuffer[i];
        //                }

        //                chunk.WaveBuffer.SetFrameChange (0);

        //                ModuleApi.ConsoleLog("Normalized audio with factor: " + factor.ToString("N2"));
        //            }
        //        }
        //    }
        //}

        //private void ButtonResampleClick(object sender, RoutedEventArgs e)
        //{
        //    int desiredFrequency = Convert.ToInt32(resample_freq.Text);

        //    foreach (WaveTrack track in AudioEngine.Instance.Project.TrackList)
        //    {
        //        bool resample = false;

        //        foreach (WaveChunk chunk in track.TrackChunks)
        //        {
        //            if (chunk.IsSelected)
        //            {
        //                resample = true;
        //            }
        //        }

        //        if (resample)
        //        {
        //            try
        //            {
        //                track.SampleRate = desiredFrequency;

        //                //
        //                // Load resampled audio back into audio engine
        //                //

        //                ModuleApi.ConsoleLog("Resampled audio with: " + desiredFrequency + " Hz");

        //            }
        //            catch (Exception ex)
        //            {
        //                ModuleApi.ConsoleLog("Resample error: " + ex.Message);
        //            }
        //        }
        //    }
        //}
    }
}
